package adsi.persistence;

import java.sql.*;
import java.util.*;
import java.util.logging.*;

import adsi.domain.*;

public class MaintenanceFactory {

    private final static MaintenanceFactory instance = new MaintenanceFactory();
    private List<Maintenance> list;
    private Database db;

    private MaintenanceFactory() {
        db = Database.getInstance();
        load();
    }

    public static MaintenanceFactory getInstance() {
        return instance;
    }

    public void load() {
        ResultSet rs = null;
        String sql = "";
        String err;
        list = new ArrayList();

        try {
            sql = "SELECT * from mantenimientos ORDER BY idMantenimientos";
            rs = db.executeQuery(sql);
            list = makeListOfMaintenances(rs);
        } catch (DataServiceException ex) {
            err = "Error en la conexión con la base de datos.";
            Logger.getLogger("logger").log(Level.WARNING, err, ex);
        } finally {
            db.closeRS(rs);
        }
    }

    public Maintenance buildMaintenance(int ID, String description, int duration) {
        return new Maintenance(ID, description, duration);
    }

    private List<Maintenance> makeListOfMaintenances(ResultSet rs) {
        List<Maintenance> result = new ArrayList();
        Maintenance m;
        String err;

        try {
            while (rs.next()) {
                m = new Maintenance(rs.getLong(1), rs.getString(2), rs.getInt(3));
                result.add(m);
            }
        } catch (SQLException ex) {
            err = "Error al recuperar los registros de Mantenimientos.";
            Logger.getLogger("logger").log(Level.WARNING, err, ex);
        }

        return result;
    }

    /**
     * Retrieves the Maintenance object corresponding to the specified ID from the 
     * persistent medium. If the ID does not exist in the persisten medium, a 
     * DataServiceException is thrown.
     *
     * @param  ID                   Unique ID of the Maintenance object stored in the 
     *                              persistent medium.
     * @return                      the Maintenance object corresponing to the 
     *                              specifyed ID.
     * @throws DataServiceException If a problem ocurrs when recovering the object
     *                              from the persistent medium.
     * @throws EntityException      If there where errors when creating the 
     *                              Maintenance object to return.
     * @see                         DataServiceModel
     */
    public synchronized Maintenance retrieveMaintenance(long ID) {
        Maintenance result = null;

        for (Iterator it = list.iterator(); it.hasNext();) {
            Maintenance m = (Maintenance) it.next();
            if (m.getID() == ID) {
                result = m;
                break;
            }
        }

        return result;
    }

    public Comparator<Maintenance> getComparator(String type) {
        if ("description".equals(type)) {
            return new Comparator<Maintenance>() {

                public int compare(Maintenance m1, Maintenance m2) {
                    return m1.getDescription().compareToIgnoreCase(m2.getDescription());
                }
            };
        } else {
            return new Comparator<Maintenance>() {

                public int compare(Maintenance m1, Maintenance m2) {
                    return  m1.getDuration() - m2.getDuration();
                }
            };
        }
    }

    public List<Maintenance> orderMaintenances(List<Maintenance> mans, String order) {
        Comparator<Maintenance> comparator = getComparator(order);
        
        Collections.sort(mans, comparator);

        return mans;
    }

    /**
     * Retrieves all the Maintenance objects stored on the persistent medium. 
     *
     * @return                      A List containing all the Maintenance 
     *                              objects stored on the persistent medium. 
     * @throws DataServiceException If a problem ocurrs when recovering the objects
     *                              from the persistent medium.
     * @throws EntityException      If there where errors when creating the Elements
     *                              for the List.
     * @see                         DataServiceModel
     */
    public synchronized List<Maintenance> retrieveMaintenances(String filter, String order) {
        return orderMaintenances(list, order);
    }

    /**
     * Retrieves the Maintenance objects stored on the persistent medium whose 
     * description attribute contains the description substring. 
     *
     * @param  description          A string that will be looked for in the  
     *                              description attribute of the stored objects to 
     *                              be retrieved.
     * @return                      A Map containing the Maintenance ID's as
     *                              the key and their corresponding Maintenance 
     *                              objects as the object asociated to the key for
     *                              the stored objects whose description contains 
     *                              the specifyed description substring.
     * @throws DataServiceException If a problem ocurrs when recovering the data
     *                              from the persistent medium.
     * @throws EntityException      If there where errors when creating the Elements
     *                              for the List.
     * @see                         DataServiceModel
     */
    public synchronized List<Maintenance> retrieveMaintenancesLike(String description) {
        List<Maintenance> result = new ArrayList();

        for (Maintenance m : list) {
            if (m.getDescription().toLowerCase().indexOf(description.toLowerCase().trim()) != -1) {
                result.add(m);
            }
        }

        return result;
    }

    /**
     * Retrieves the Maintenance objects stored on the persistent medium whose 
     * length attribute is within the specified range. 
     *
     * @param  minDays              Minimum length (in days) for the Maintainance
     *                              object. Must be lower than or equal to maxDays, 
     *                              otherwhise a DataServiceException will be thrown.
     * @param  maxDays              Maximum length (in days) for the Maintainance
     *                              object. Must be greater than or equal to minDays,
     *                              otherwhise a DataServiceException will be thrown.
     * @return                      A List containing the Maintenance objects
     *                              whose length attribute is within the 
     *                              specifyed range.
     * @throws DataServiceException If a problem ocurrs when recovering the data
     *                              from the persistent medium or if range is invalid.
     * @throws EntityException      If there where errors when creating the Elements
     *                              for the List.
     * @see                         DataServiceModel
     */
    public synchronized List<Maintenance> retrieveMaintenancesInRange(int minDays, int maxDays) {
        List<Maintenance> result = new ArrayList();

        System.out.println(minDays + "m" + maxDays);
        for (Maintenance m : list) {
            if (m.getDuration() >= minDays) {
                if (maxDays != -1 && m.getDuration() <= maxDays) {
                    result.add(m);
                } else if (maxDays == -1) {
                    result.add(m);
                }
            }
        }

        return result;
    }

    /**
     * Saves the Maintenance object in the persistent medium.
     * <p>
     * This method returns the unique ID assigned to the object by the persistent 
     * medium. If a value of -1 is returned, it means the object was not stored.
     *
     * @param  m                    Maintenance object to be stored.
     * @return                      the unique ID assigned by the persistent medium
     * @throws DataServiceException If a problem ocurrs when giving persistence to
     *                              the object.
     * @see                         DataServiceModel
     * @see                         Maintenance
     */
    public boolean saveMaintenance(Maintenance m) {
        int queryRes = 0;

        try {
            if (m.getID() < 0) {
                queryRes = insertMaintenance(m);
            } else {
                queryRes = updateMaintenance(m);
            }
        } catch (DataServiceException e) {
            e.printStackTrace();
        }

        return queryRes > 0;
    }

    public synchronized long getMaxID() {
        Vector<Integer> v = new Vector();
        
        long max = 1;
        for (Maintenance m: list) {
            if (m.getID() > max) {
                max = m.getID();
            }
        }
        
        return max;
    }
    
    public synchronized int insertMaintenance(Maintenance m) throws DataServiceException {
        String sql = "";
        int queryRes = 0;
        long ID = getMaxID() + 1;

        sql = "INSERT INTO mantenimientos " +
                "(idMantenimientos, Descripcion, DiasDuracion)" +
                "VALUES (" + ID + ", '" +
                m.getDescription() + "', " +
                m.getDuration() + ")";
        queryRes = db.executeUpdate(sql);

        if (queryRes > 0) {
            m.setID(ID);
            list.add(m);
        }

        return queryRes;
    }

    public synchronized int updateMaintenance(Maintenance m) throws DataServiceException {
        String sql = "";
        int queryRes = 0;

        sql = "UPDATE mantenimientos SET " +
                "Descripcion = '" + m.getDescription() + "', " +
                "DiasDuracion = " + m.getDuration() + " " +
                "WHERE idMantenimientos =" + m.getID();
        queryRes = db.executeUpdate(sql);

        if (queryRes > 0) {
            for (Iterator it = list.iterator(); it.hasNext();) {
                Maintenance aux = (Maintenance) it.next();
                if (aux.getID() == m.getID()) {
                    aux.setDescription(m.getDescription());
                    aux.setDuration(m.getDuration());
                    break;
                }
            }
        }

        return queryRes;
    }

    /**
     * Marks the stored Maintenance object corresponding to the specified ID
     * as deleted in the persistent medium. 
     * <p>
     * Maintenance object can be marked as deleted only if it is not currently 
     * referenced from any EquipmentMaintenance or ProgrammedMaintenance object (in 
     * the persistent medium). If there are objects marked as deleted that reference
     * the Maintenance object being deleted, deletion can not be performed, in which
     * case executing a call to the purge method of the corresponding
     * DataServiceModel instance might enable the marking of the object as deleted. 
     *
     * @param  ID                   Unique ID of the Maintenance object on the 
     *                              persistent medium.
     * @throws DataServiceException If a problem ocurrs when marking the stored 
     *                              object as deleted.
     * @see                         DataServiceModel
     */
    public synchronized boolean deleteMaintenance(long ID) throws DataServiceException {
/*      String sql;
        int queryRes;
        Maintenance m = null;

        sql = "DELETE FROM mantenimientos WHERE idMantenimientos = " + ID;
        queryRes = db.executeUpdate(sql);

        if (queryRes > 0) {
            m = retrieveMaintenance(ID);
            list.remove(m);
        }

        return queryRes > 0;
 */
        return false;
    }
    /*
    public synchronized void deleteMaintenance(long ID) {
    String sql;
    String err;
    int queryRes;
    
    try {
    sql = "UPDATE mantenimientos SET Borrado = TRUE WHERE idMantenimientos = " + ID;
    queryRes = db.executeUpdate(sql);
    
    if (queryRes == 0) {
    throw new DataServiceException("Ningún registro fue marcado como borrado.");
    } else {
    //This condition should never occur, since persistence medium
    //is responsible of maintaining uniqueness of keys.
    err = "Más de un registro fue marcado como borrado.";
    Logger.getLogger("logger").log(Level.SEVERE, err, sql);
    throw new DataServiceException(err);
    }
    } catch (DataServiceException ex) {
    err = "Error al marcar como borrado el registro con ID " + ID + ".";
    Logger.getLogger("logger").log(Level.WARNING, err, ex);
    throw new DataServiceException(err);
    }
    }
    
    
    /**
     * Removes the deletion mark from the object corresponding to the ID.
     *
     * @throws DataServiceException If a problem ocurrs when removing the deletion 
     *                              mark from the object on the persistent medium.
     * @see                         DataServiceModel
     */
    /*
    public synchronized void undeleteMaintenance(long ID) {
    String sql;
    String err;
    int queryRes;
    
    try {
    sql = "UPDATE mantenimientos SET Borrado = FALSE WHERE idMantenimientos = " + ID;
    queryRes = db.executeUpdate(sql);
    
    if (queryRes == 0) {
    throw new DataServiceException("Ningún registro fue desmarcado como borrado.");
    } else {
    //This condition should never occur, since persistence medium
    //is responsible of maintaining uniqueness of keys.
    err = "Más de un registro fue desmarcado como borrado.";
    Logger.getLogger("logger").log(Level.SEVERE, err, sql);
    throw new DataServiceException(err);
    }
    } catch (DataServiceException ex) {
    err = "Error al desmarcar como borrado el registro con ID " + ID + ".";
    Logger.getLogger("logger").log(Level.WARNING, err, ex);
    throw new DataServiceException(err);
    }
    }
     */
}
